using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using NBusiness.Templates;
using System.IO.IsolatedStorage;
using NBusiness.CodeDom;
using NBusiness.Utilities;
using System.IO;
using Microsoft.VisualStudio.Package;

namespace NBusiness.VisualStudio
{
    public partial class ESharpSchemaUpdaterProgress : Form
    {
        string _projectName;
        EntityTemplate[] _templates;
        Entity[] _entities;

        public ESharpSchemaUpdaterProgress(string projectName, EntityTemplate[] templates)
            : this()
        {
            _projectName = projectName;
            _templates = templates;
            LoadUpdaters();
        }

        public ESharpSchemaUpdaterProgress()
        {
            InitializeComponent();
        }

        private void LoadUpdaters()
        {
            listView1.Items.Clear();
            foreach (EntityTemplate template in _templates)
            {
                ISchemaUpdater updater = TypeLoader.Load<ISchemaUpdater>(template.In, template.Type);
                if (updater != null)
                {
                    ListViewItem lvi = new ListViewItem(updater.Name);
                    lvi.Tag = template;
                    lvi.Checked = true;
                    listView1.Items.Add(lvi);
                }
            }
        }

        void updater_Progress(object sender, SchemaUpdaterProgressArgs e)
        {
            this.Invoke((MethodInvoker)delegate()
            {
                toolStripProgressBar1.Value = (int)(e.Progress * 100d);

                toolStripStatusLabel1.Text = e.Message;
            });
        }

        private void buttonUpdate_Click(object sender, EventArgs e)
        {
            Disable();
            if (listView1.SelectedItems.Count > 0)
            {
                ListViewItem lvi = listView1.SelectedItems[0];
                EntityTemplate template = lvi.Tag as EntityTemplate;
                ISchemaUpdater updater = TypeLoader.Load<ISchemaUpdater>(template.In, template.Type);
                updater.Progress += new EventHandler<SchemaUpdaterProgressArgs>(updater_Progress);
                updater.Completed += new EventHandler(updater_Completed);

                MethodInvoker method = new MethodInvoker(delegate()
                {
                    try
                    {
                        SchemaUpdaterOptions options = GetOptionsFromPrivateStorage(updater.GetType(), updater.GetDefaultOptions().GetType());

                        bool update = true;
                        if (options == null)
                        {
                            options = updater.GetDefaultOptions();
                            if (updater.EditOptions(options) == SchemaOptionsEditResult.Continue)
                            {
                                SaveOptionsIntoPrivateStorage(options, updater.GetType());
                            }
                            else update = false;
                        }

                        if (update)
                        {
                            updater.UpdateSchema(options, template.Entities.ToArray());
                        }
                    }
                    catch (Exception ex)
                    {
                        // we have to do this otherwise it will blow up VS...
                        MessageBox.Show(ex.Message, SR.GetString(SR.Error), MessageBoxButtons.OK);
                        this.BeginInvoke((MethodInvoker)delegate()
                        {
                            Enable();
                        });
                    }
                });

                method.BeginInvoke(new AsyncCallback(delegate(IAsyncResult result)
                {
                    method.EndInvoke(result);
                }), null);
            }
            else
            {
                Enable();
            }
        }

        void updater_Completed(object sender, EventArgs e)
        {
            this.Invoke((MethodInvoker)delegate()
            {
                Enable();
            });
        }

        void Disable()
        {
            listView1.Enabled = false;
            buttonUpdate.Enabled = false;
            buttonEdit.Enabled = false;
            buttonClose.Enabled = false;
        }

        void Enable()
        {
            listView1.Enabled = true;
            buttonUpdate.Enabled = true;
            buttonEdit.Enabled = true;
            buttonClose.Enabled = true;

            toolStripProgressBar1.Maximum = 100;
            toolStripProgressBar1.Minimum = 0;
            toolStripProgressBar1.Value = 0;
            toolStripStatusLabel1.Text = string.Empty;
        }

        private void buttonEdit_Click(object sender, EventArgs e)
        {
            Disable();
            try
            {
                if (listView1.SelectedItems.Count > 0)
                {
                    ListViewItem lvi = listView1.SelectedItems[0];
                    EntityTemplate template = lvi.Tag as EntityTemplate;
                    ISchemaUpdater updater = TypeLoader.Load<ISchemaUpdater>(template.In, template.Type);
                    SchemaUpdaterOptions options = GetOptionsFromPrivateStorage(updater.GetType(), updater.GetDefaultOptions().GetType());

                    if (options == null)
                        options = updater.GetDefaultOptions();

                    if (updater.EditOptions(options) == SchemaOptionsEditResult.Continue)
                    {
                        SaveOptionsIntoPrivateStorage(options, updater.GetType());
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, SR.GetString(SR.Error), MessageBoxButtons.OK);
            }
            finally
            {
                Enable();
            }
        }

        #region Private Storage
        private SchemaUpdaterOptions GetOptionsFromPrivateStorage(Type t, Type optionsType)
        {
            SchemaUpdaterOptions options = null;
            using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly())
            {
                if (storage.GetDirectoryNames(_projectName).Length == 0)
                    storage.CreateDirectory(_projectName);

                string isolatedName = Path.Combine(_projectName, t.FullName);

                string[] fileNames = storage.GetFileNames(isolatedName);
                if (fileNames.Length > 0)
                {
                    using (IsolatedStorageFileStream reader = new IsolatedStorageFileStream(isolatedName, FileMode.Open, storage))
                    {
                        if (reader.Length > 0)
                        {
                            byte[] buffer = new byte[reader.Length];
                            reader.Read(buffer, 0, (int)reader.Length);
                            try
                            {
                                options = (SchemaUpdaterOptions)Serialization.XMLDeserialize(Encoding.UTF8.GetString(buffer), optionsType);
                            }
                            catch { }
                        }
                    }
                }
            }
            return options;
        }

        private void SaveOptionsIntoPrivateStorage(SchemaUpdaterOptions options, Type t)
        {
            string isolatedName = Path.Combine(_projectName, t.FullName);
            using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly())
            {
                if (storage.GetDirectoryNames(_projectName).Length == 0)
                    storage.CreateDirectory(_projectName);

                string xml = Serialization.XMLSerialize(options);
                byte[] buffer = Encoding.UTF8.GetBytes(xml);
                using (IsolatedStorageFileStream writer = new IsolatedStorageFileStream(isolatedName, FileMode.Create, storage))
                {
                    writer.Write(buffer, 0, buffer.Length);
                }
            }
        }
        #endregion
    }
}
